/* ****************************************************************************
 *
 * Copyright (c) Microsoft Corporation. 
 *
 * This source code is subject to terms and conditions of the Microsoft Public License. A 
 * copy of the license can be found in the License.html file at the root of this distribution. If 
 * you cannot locate the  Microsoft Public License, please send an email to 
 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 * by the terms of the Microsoft Public License.
 *
 * You must not remove this notice, or any other, from this software.
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 * ***************************************************************************/


#include "stdafx.h"
#include <pgl/core/PGLMapVector.h>
#include <pgl/core/PGLMapVectorPropPage.h>
#include <pgl/core/PGLDataVectors.h>
#include <pgl/core/DataRegistry.h>

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif



PGL_IMPLEMENT_DYNCREATE(CPGLMapVector, CPGLMap);

//! Save settings
void CPGLMapVector::SerializeXML(CPGLArchive& ar)
{
	CString strPos;	strPos.Format(_T("%u"),(DWORD)this);
	static const TCHAR szTag[] = _T("CPGLMapVector");
	markup::CMarkupArchive& xml = *((markup::CMarkupArchive*)ar.GetMarkup());
	if(ar.IsStoring())
	{
		ASSERT(m_pVx);
		ASSERT(m_pVy);
		xml.AddChildElem(szTag);
		xml.AddChildAttrib(_T("Name"),GetName());
		xml.IntoElem();

			/////////////////////////////////////////////////////////
			// Adding base class
			CPGLMap::SerializeXML(ar);

			xml.AddChildElemEx(_T("LineWidth"),m_fLineWidth);
			xml.AddChildElem(_T("Vx"));
			xml.IntoElem();
				m_pVx->SerializeXML(ar);
			xml.OutOfElem();
			xml.AddChildElem(_T("Vy"));
			xml.IntoElem();
				m_pVy->SerializeXML(ar);
			xml.OutOfElem();

		xml.OutOfElem();
	}
	else
	{
		if  (!xml.FindChildElem(szTag))
				return;

		xml.IntoElem();
			CPGLMap::SerializeXML(ar);

			xml.FindGetChildData(_T("LineWidth"), m_fLineWidth);

			PGL_SERIALIZE_LOAD_DATA( strPos , Vx , m_pVx );
			PGL_SERIALIZE_LOAD_DATA( strPos , Vy , m_pVy );

		xml.OutOfElem();
	}
}


#ifdef _DEBUG
void CPGLMapVector::Dump( CDumpContext& dc ) const
{
    // call base class function first
    CPGLMap::Dump( dc );

    // now do the stuff for our specific class
	dc << _T("CPGLMapVector ID ") << GetID() << "\n";
}

void CPGLMapVector::AssertValid() const
{
    // call inherited AssertValid first
    CPGLMap::AssertValid();
} 
#endif


CPGLMapVector::CPGLMapVector()
: CPGLMap()
{
	m_dNormMin=0;
	m_dNormMax=1;
	m_fLineWidth=1;
	
	LoadBitmap(IDB_PGL_MAPVECTOR_BITMAP);
}

CPGLMapVector& CPGLMapVector::operator = (const CPGLMapVector& l)
{
	// prevent self copy
	if (&l != this)
	{
		// invoke CPGLMap copy assignement operator
		this->CPGLMap::operator=(l);

		m_dNormMin=l.m_dNormMin;
		m_dNormMax=l.m_dNormMax;
		m_fLineWidth=l.m_fLineWidth;

		ClearData();
		m_pVx = l.m_pVx->Clone();
		m_pVy = l.m_pVy->Clone();

		LoadBitmap(IDB_PGL_MAPVECTOR_BITMAP);
	}
	return *this;
}

CPGLMapVector::~CPGLMapVector() 
{
	ClearData();
};

void CPGLMapVector::AddPropertyPage(CPropertySheet* pPropSheet)
{
	ASSERT_VALID(pPropSheet);
	// call own functions
	CPGLMapVectorPropPage* propPage=new CPGLMapVectorPropPage(this);
	pPropSheet->AddPage(propPage);

	// first call base class function
	CPGLMap::AddPropertyPage(pPropSheet);
}

/// plotting to EPS file
void CPGLMapVector::PlotGfx(gfxinterface::CGfxInterface& gfx)
{
	using namespace contour;
	// first if it is visible
	if (!IsVisible())
		return;
	if (!IsInLayer(gfx.GetLayer()))
		return;

	const TLattice<float>* pLattice=GetLattice();
	if (!m_pVx || !m_pVy || !pLattice)
		return;

	// calling base class plot
	CPGLMap::PlotGfx(gfx);

	GFX_ADDCOMMENT(gfx,"--- CPGLMapVector ---");	
	gfx.PushState();
	gfx.SetFillColor(GetColor().GetRed(), GetColor().GetGreen(), GetColor().GetBlue(), GetColor().GetAlpha());
	gfx.SetColor(GetColor().GetRed(), GetColor().GetGreen(), GetColor().GetBlue(), GetColor().GetAlpha());
	gfx.SetLineWidth(m_fLineWidth);
	gfx.SetDash(_T(""));

	gfx.DrawVectorField(*GetLattice(), *m_pVx, *m_pVy, (float)0.1);
	gfx.PopState();
}

void CPGLMapVector::SetDatas(const std::vector<double>& vVx, const std::vector<double>&  vVy, bool bMakeOwnCopy)
{
	if (bMakeOwnCopy)
	{
		SetDatas(CPGLVectorDPtr(new CPGLVectorD(vVx)), CPGLVectorDPtr(new CPGLVectorD(vVy)));
	}
	else
	{
		SetDatas(CPGLVectorRefDPtr(new CPGLVectorRefD(vVx)), CPGLVectorRefDPtr(new CPGLVectorRefD(vVy)));
	}
}
void CPGLMapVector::SetDatas(const std::vector<float>& vVx, const std::vector<float>&  vVy, bool bMakeOwnCopy)
{
	if (bMakeOwnCopy)
	{
		SetDatas(CPGLVectorFPtr(new CPGLVectorF(vVx)), CPGLVectorFPtr(new CPGLVectorF(vVy)));
	}
	else
	{
		SetDatas(CPGLVectorRefFPtr(new CPGLVectorRefF(vVx)), CPGLVectorRefFPtr(new CPGLVectorRefF(vVy)));
	}
}
void CPGLMapVector::SetDatas(const std::vector<int>& vVx, const std::vector<int>&  vVy, bool bMakeOwnCopy)
{
	if (bMakeOwnCopy)
	{
		SetDatas(CPGLVectorIPtr(new CPGLVectorI(vVx)), CPGLVectorIPtr(new CPGLVectorI(vVy)));
	}
	else
	{
		SetDatas(CPGLVectorRefIPtr(new CPGLVectorRefI(vVx)), CPGLVectorRefIPtr(new CPGLVectorRefI(vVy)));
	}
}
void CPGLMapVector::SetDatas(const std::vector<BYTE>& vVx, const std::vector<BYTE>&  vVy, bool bMakeOwnCopy)
{
	if (bMakeOwnCopy)
	{
		SetDatas(CPGLVectorBPtr(new CPGLVectorB(vVx)), CPGLVectorBPtr(new CPGLVectorB(vVy)));
	}
	else
	{
		SetDatas(CPGLVectorRefBPtr(new CPGLVectorRefB(vVx)), CPGLVectorRefBPtr(new CPGLVectorRefB(vVy)));
	}
}


//! Sets the data for the vector field
void CPGLMapVector::SetDatas(CPGLDataPtr pVx, CPGLDataPtr  pVy)
{
	using namespace contour;
	UINT i;
	double norm;

	ClearData();

	m_pVx = pVx;
	m_pVy = pVy;

	TLattice<float>* pLattice=GetLattice();
	if (!m_pVx || !m_pVy || !pLattice)
		return;

	// getting address of buffers
	if ((pVx->size()==0) || (pVy->size()==0))
	{
		m_dNormMin=0;
		m_dNormMax=1;
		return;
	}

	// finding min and max
	// init loop
	m_dNormMin=m_dNormMax=(*m_pVx)[0]*(*m_pVx)[0]+(*m_pVy)[0]*(*m_pVy)[0];
	for (i=0;i<pLattice->GetVertexSize();i++)
	{
		norm=(*m_pVx)[i]*(*m_pVx)[i]+(*m_pVy)[i]*(*m_pVy)[i];
		m_dNormMin=__min(m_dNormMin,norm);
		m_dNormMax=__max(m_dNormMax,norm);
	}

	m_dNormMin=sqrt(m_dNormMin);
	m_dNormMax=sqrt(m_dNormMax);

	PostUpdateExtent();
}


void CPGLMapVector::ClearData()
{
	m_pVx.reset();
	m_pVy.reset();
}
